//! 文件系统数据源
//! 
//! 提供基于文件系统的数据查询功能

use std::path::{Path, PathBuf};
use async_trait::async_trait;
use serde_json::{Value, json};
use tokio::fs;

use crate::{DataSource, DataSourceQuery, DataSourceResult, DataSourceStats};

/// 文件系统数据源
pub struct FileSystemDataSource {
    name: String,
    description: String,
    connected: bool,
    root_path: PathBuf,
}

impl FileSystemDataSource {
    /// 创建新的文件系统数据源
    pub fn new<P: AsRef<Path>>(root_path: P) -> Self {
        Self {
            name: "文件系统数据源".to_string(),
            description: "基于文件系统的数据查询，支持文件和目录操作".to_string(),
            connected: false,
            root_path: root_path.as_ref().to_path_buf(),
        }
    }
    
    /// 列出目录内容
    async fn list_directory(&self, path: &Path) -> anyhow::Result<Value> {
        let mut entries = Vec::new();
        let mut dir = fs::read_dir(path).await?;
        
        while let Some(entry) = dir.next_entry().await? {
            let metadata = entry.metadata().await?;
            let file_name = entry.file_name().to_string_lossy().to_string();
            
            entries.push(json!({
                "name": file_name,
                "type": if metadata.is_dir() { "directory" } else { "file" },
                "size": metadata.len(),
                "modified": metadata.modified()
                    .ok()
                    .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
                    .map(|d| d.as_secs())
            }));
        }
        
        Ok(json!({
            "path": path.to_string_lossy(),
            "entries": entries,
            "count": entries.len()
        }))
    }
    
    /// 读取文件内容
    async fn read_file(&self, path: &Path) -> anyhow::Result<Value> {
        let content = fs::read_to_string(path).await?;
        let metadata = fs::metadata(path).await?;
        
        Ok(json!({
            "path": path.to_string_lossy(),
            "content": content,
            "size": metadata.len(),
            "lines": content.lines().count()
        }))
    }
    
    /// 获取文件信息
    async fn get_file_info(&self, path: &Path) -> anyhow::Result<Value> {
        let metadata = fs::metadata(path).await?;
        
        Ok(json!({
            "path": path.to_string_lossy(),
            "type": if metadata.is_dir() { "directory" } else { "file" },
            "size": metadata.len(),
            "readonly": metadata.permissions().readonly(),
            "modified": metadata.modified()
                .ok()
                .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
                .map(|d| d.as_secs()),
            "created": metadata.created()
                .ok()
                .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
                .map(|d| d.as_secs())
        }))
    }
    
    /// 执行文件系统查询
    async fn execute_fs_query(&self, query: &str) -> anyhow::Result<Value> {
        let query = query.trim();
        
        if query.starts_with("ls ") || query.starts_with("list ") {
            let path_str = if query.starts_with("ls ") {
                query.strip_prefix("ls ").unwrap()
            } else {
                query.strip_prefix("list ").unwrap()
            };
            
            let path = if path_str.starts_with('/') {
                PathBuf::from(path_str)
            } else {
                self.root_path.join(path_str)
            };
            
            self.list_directory(&path).await
        } else if query.starts_with("cat ") || query.starts_with("read ") {
            let path_str = if query.starts_with("cat ") {
                query.strip_prefix("cat ").unwrap()
            } else {
                query.strip_prefix("read ").unwrap()
            };
            
            let path = if path_str.starts_with('/') {
                PathBuf::from(path_str)
            } else {
                self.root_path.join(path_str)
            };
            
            self.read_file(&path).await
        } else if query.starts_with("stat ") || query.starts_with("info ") {
            let path_str = if query.starts_with("stat ") {
                query.strip_prefix("stat ").unwrap()
            } else {
                query.strip_prefix("info ").unwrap()
            };
            
            let path = if path_str.starts_with('/') {
                PathBuf::from(path_str)
            } else {
                self.root_path.join(path_str)
            };
            
            self.get_file_info(&path).await
        } else if query == "pwd" {
            Ok(json!({
                "current_directory": self.root_path.to_string_lossy()
            }))
        } else {
            Err(anyhow::anyhow!("不支持的文件系统查询: {}", query))
        }
    }
}

#[async_trait]
impl DataSource for FileSystemDataSource {
    fn name(&self) -> &str {
        &self.name
    }
    
    fn description(&self) -> &str {
        &self.description
    }
    
    async fn connect(&mut self) -> anyhow::Result<()> {
        tracing::info!("连接到文件系统数据源: {:?}", self.root_path);
        
        // 检查根路径是否存在
        if !self.root_path.exists() {
            return Err(anyhow::anyhow!("根路径不存在: {:?}", self.root_path));
        }
        
        self.connected = true;
        Ok(())
    }
    
    async fn disconnect(&mut self) -> anyhow::Result<()> {
        tracing::info!("断开文件系统数据源连接");
        self.connected = false;
        Ok(())
    }
    
    async fn is_connected(&self) -> bool {
        self.connected
    }
    
    async fn execute_query(&mut self, query: DataSourceQuery) -> anyhow::Result<DataSourceResult> {
        if !self.connected {
            return Err(anyhow::anyhow!("数据源未连接"));
        }
        
        let start_time = std::time::Instant::now();
        
        tracing::debug!("执行文件系统查询: {}", query.content);
        
        match self.execute_fs_query(&query.content).await {
            Ok(data) => {
                let duration = start_time.elapsed();
                let rows_processed = if let Some(entries) = data.get("entries") {
                    entries.as_array().map(|arr| arr.len() as u64).unwrap_or(1)
                } else {
                    1
                };
                
                Ok(DataSourceResult {
                    success: true,
                    data,
                    error: None,
                    stats: DataSourceStats {
                        execution_time_ms: duration.as_millis() as f64,
                        rows_processed,
                        bytes_processed: query.content.len() as u64,
                    },
                })
            }
            Err(e) => {
                let duration = start_time.elapsed();
                Ok(DataSourceResult {
                    success: false,
                    data: json!({}),
                    error: Some(e.to_string()),
                    stats: DataSourceStats {
                        execution_time_ms: duration.as_millis() as f64,
                        rows_processed: 0,
                        bytes_processed: query.content.len() as u64,
                    },
                })
            }
        }
    }
    
    async fn health_check(&self) -> anyhow::Result<Value> {
        let root_exists = self.root_path.exists();
        let root_readable = if root_exists {
            fs::metadata(&self.root_path).await.is_ok()
        } else {
            false
        };
        
        Ok(json!({
            "status": if self.connected { "connected" } else { "disconnected" },
            "name": self.name,
            "root_path": self.root_path.to_string_lossy(),
            "root_exists": root_exists,
            "root_readable": root_readable
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;

    #[tokio::test]
    async fn test_file_system_data_source() {
        // 使用当前目录作为测试根路径
        let current_dir = env::current_dir().unwrap();
        let mut source = FileSystemDataSource::new(&current_dir);
        
        // 测试连接
        assert!(!source.is_connected().await);
        source.connect().await.unwrap();
        assert!(source.is_connected().await);
        
        // 测试pwd查询
        let query = DataSourceQuery {
            id: "test".to_string(),
            content: "pwd".to_string(),
            parameters: std::collections::HashMap::new(),
        };
        
        let result = source.execute_query(query).await.unwrap();
        assert!(result.success);
        
        // 测试ls查询
        let query = DataSourceQuery {
            id: "test".to_string(),
            content: "ls .".to_string(),
            parameters: std::collections::HashMap::new(),
        };
        
        let result = source.execute_query(query).await.unwrap();
        assert!(result.success);
        
        // 测试健康检查
        let health = source.health_check().await.unwrap();
        assert_eq!(health["status"], "connected");
        assert_eq!(health["root_exists"], true);
        
        // 测试断开连接
        source.disconnect().await.unwrap();
        assert!(!source.is_connected().await);
    }
}
